﻿using System;
using System.Collections.Generic;
using System.Text;
using MigratorCore.Actions;
using MigratorCore.Bases;
using MigratorCore.Status;
using MigratorCore.Objects;
using MigratorCore;
using System.Threading;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Data;

namespace Migrator.CommunityServer.version2007_1
{
    public enum PasswordType { Email, Random, Blank, Default };

    public class UsersDestination : IDestinationAction
    {
        #region IAction Members

        private Settings settings;
        public Settings Settings
        {
            get
            {
                if (settings == null)
                {
                    settings = new Settings();
                    settings.Add("ConnectionString", "server=(localhost);uid=;pwd=;Trusted_Connection=yes;database=CommunityServer");
                    settings.Add("PasswordType", PasswordType.Default);
                    settings.Add("Application Name", "dev");
                    settings.Add("Default Password", "");
                }
                return settings;
            }
        }

        public string Name
        {
            get { return "Users Destination"; }
        }

        private Status status;
        public Status Status
        {
            get
            {
                if (status == null)
                    status = new Status();
                return status;
            }
        }

        private ObjectSet objects;
        public ObjectSet Objects
        {
            get
            {
                if (objects == null) objects = new ObjectSet();
                return objects;
            }
            set
            {
                objects = value;
            }
        }

        public ActionType ActionType
        {
            get
            {
                return ActionType.Users;
            }
        }

        #endregion

        private bool userexists(List<User> users, User user)
        {
            foreach (User u in users)
                if (u.Email == user.Email)
                    return true;
            return false;
        }

        #region IDestinationAction Members

        public void Set()
        {
            if (objects == null | objects.Count < 1)
            {
                status.AddEvent(new Event(EventType.CriticalError, "Object Set Blank", "Object Set is Blank, unable to continue", DateTime.Now));
                return;
            }
            List<string> roles = new List<string>();
            List<string> roles2 = new List<string>();
            List<User> users = new List<User>();
            SqlConnection con = new SqlConnection(settings["ConnectionString"].ToString());
            SqlDataReader read;
            SqlCommand cmd;
            int x = 0;
            int sitesettingid;
            #region Get Current Roles
            cmd = new SqlCommand("exec [dbo].[cs_Roles_Get] @ApplicationName = '" + settings["Application Name"].ToString() + "'", con);
            try
            {
                con.Open();
                read = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
            }
            catch (Exception e)
            {
                con.Close();
                con.Dispose();
                status.Completed = 100;
                status.AddEvent(new Event(EventType.CriticalError, "Data Connection Failed!", e.Message, e, DateTime.Now));
                return;
            }
            status.AddEvent(new Event(EventType.Information, "Loading Current Roles", "Loading Roles from the Destination Database", DateTime.Now));
            
            while (read.Read())
            {
                x++;
                roles.Add(read.GetGuid(0).ToString());
                roles2.Add(read.GetString(1));
            }
            read.Close();
            status.Completed = 5;
            status.AddEvent(new Event(EventType.Information, "Loaded " + x.ToString() + " Roles", "Loaded " + x.ToString() + " Roles from the Destination Database", DateTime.Now));
            cmd.Dispose();
            #endregion
            #region Get Current Users
            cmd = new SqlCommand("EXEC [dbo].[aspnet_Membership_GetAllUsers] @ApplicationName = '" + settings["Application Name"] + "', @PageIndex = 0, @PageSize = 99999999", con);
            con.Open();
            read = cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
            x = 0;
            status.AddEvent(new Event(EventType.Information, "Loading Current Users", "Loading Users from the Destination Database", DateTime.Now));
            while (read.Read())
            {
                x++;
                User user = new User();
                user.Name = read.GetString(0);
                user.Email = read.GetString(1);
                users.Add(user);
            }
            read.Close();
            status.Completed = 10;
            status.AddEvent(new Event(EventType.Information, "Loaded " + x.ToString() + " Users", "Loaded " + x.ToString() + " Users from the Destination Database", DateTime.Now));
            cmd.Dispose();
            #endregion
            #region Get Setting ID
            cmd = new SqlCommand("SELECT [SettingsID] FROM [dbo].[cs_SiteSettings] WHERE [ApplicationName] = '" + settings["Application Name"].ToString() + "'", con);
            con.Open();
            sitesettingid = Convert.ToInt32(cmd.ExecuteScalar());
            cmd.Dispose();
            con.Close();
            #endregion
            x = 0;
            foreach (User user in objects)
            {
                x++;
                cmd = new SqlCommand();
                cmd.Connection = con;
                if (userexists(users, user))
                {
                    status.AddEvent(new Event(EventType.Duplicate, "User " + user.Name + " already exists", "User " + user.Name + "(" + user.Email + ") already exists, skipping", DateTime.Now));
                    double aa = 0.00 + objects.Count;
                    status.Completed = Convert.ToInt32(Math.Round(Convert.ToDecimal(((x + 1) / aa) * 100), 0));
                } 
                else 
                {
                    status.AddEvent(new Event(EventType.Information, "Creating User " + x + " of " + this.objects.Count, "Creating User " + x + " of " + this.objects.Count + " (" + user.Name + ")", DateTime.Now));
                    StringBuilder sb = new StringBuilder();
                    //try
                    //{
                        #region User Creation
                        //sb.AppendLine("DECLARE @UserID uniqueidentifier");
                        //sb.AppendLine("DECLARE @cs_UserID int");
                        //sb.AppendLine("DECLARE @Time DateTime");
                        #region Role Creation
                        List<string> rolenames = new List<string>();
                        rolenames.Add("Registered Users");
                        rolenames.Add("Everyone");
                        foreach (string role in user.Roles)
                        {
                            if (!roles2.Contains(role.Replace("\'", string.Empty)))
                            {
                                cmd = new SqlCommand("[dbo].[cs_Roles_CreateRole]", con);
                                cmd.CommandType = CommandType.StoredProcedure;
                                cmd.Parameters.AddWithValue("@ApplicationName", settings["Application Name"].ToString());
                                cmd.Parameters.AddWithValue("@RoleName", role);
                                cmd.Parameters.AddWithValue("@Description", "");
                                con.Open();
                                try
                                {
                                    cmd.ExecuteNonQuery();
                                    bool add = true;
                                    foreach (string r in rolenames)
                                        if (r.ToLower() == role.ToLower())
                                            add = false;
                                    if (add) rolenames.Add(role);
                                }
                                catch (Exception e) { status.AddEvent(new Event(EventType.MissingData, "Error Creating Role for User", e.Message, e, DateTime.Now)); }
                                con.Close();
                                //sb.AppendLine("EXECUTE [dbo].[cs_Roles_CreateRole] '" + settings["Application Name"].ToString() + "', '" + role.Replace("\'", string.Empty) + "', ''");
                                //roles.Add("NEW");
                                //roles2.Add(role.Replace("\'", string.Empty));
                            }
                        }
                        #endregion
                        //sb.AppendLine("SET @Time=getdate()");
                        //sb.AppendLine("SET @UserId = null");
                        string password = "";
                        #region Password Creation
                        switch ((PasswordType)settings["PasswordType"])
                        {
                            case PasswordType.Default:
                                password = settings["Default Password"].ToString();
                                break;
                            case PasswordType.Email:
                                password = user.Email;
                                break;
                            case PasswordType.Random:
                                password = "randompassword" + new Random().Next(10, 100000);
                                break;
                        }
                        #endregion
                        #region Create Base User
                        cmd = new SqlCommand("[dbo].[aspnet_Membership_CreateUser]", con);
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.Parameters.AddWithValue("@ApplicationName", settings["Application Name"].ToString());
                        cmd.Parameters.AddWithValue("@UserName", user.Name);
                        cmd.Parameters.AddWithValue("@Password", password);
                        cmd.Parameters.AddWithValue("@PasswordSalt", "");
                        cmd.Parameters.AddWithValue("@Email", user.Email);
                        cmd.Parameters.AddWithValue("@PasswordQuestion", "Your Email?");
                        cmd.Parameters.AddWithValue("@PasswordAnswer", user.Email);
                        SqlParameter IsApproved = new SqlParameter("@IsApproved", System.Data.SqlDbType.Bit);
                        IsApproved.Value = 1;
                        cmd.Parameters.Add(IsApproved);
                        SqlParameter DateUTC = new SqlParameter("@CurrentTimeUtc", System.Data.SqlDbType.DateTime);
                        DateUTC.Value = DateTime.Now.ToUniversalTime();
                        cmd.Parameters.Add(DateUTC);
                        SqlParameter CreateDate = new SqlParameter("@CreateDate", System.Data.SqlDbType.DateTime);
                        CreateDate.Value = user.Datejoined;
                        cmd.Parameters.Add(CreateDate);
                        SqlParameter UserId = new SqlParameter("@UserId", System.Data.SqlDbType.UniqueIdentifier);
                        UserId.Direction = System.Data.ParameterDirection.Output;
                        cmd.Parameters.Add(UserId);
                        con.Open();
                        //try
                        //{
                            cmd.ExecuteNonQuery();
                            #endregion
                            //con.Close();
                            Guid userid = (Guid)cmd.Parameters["@UserId"].Value;
                            #region Profile Processing
                            string values = "";
                            string keys = "";
                            Serializer.ConvertFromNameValueCollection(user.Attributes, ref keys, ref values, false);
                            #endregion
                            cmd = new SqlCommand("[dbo].[cs_user_CreateUpdateDelete]", con);
                            cmd.CommandType = CommandType.StoredProcedure;
                            SqlParameter csuserid = new SqlParameter("@cs_UserID", System.Data.SqlDbType.Int);
                            csuserid.Direction = System.Data.ParameterDirection.Output;
                            cmd.Parameters.Add(csuserid);
                            SqlParameter csuser = new SqlParameter("@UserID", System.Data.SqlDbType.UniqueIdentifier);
                            csuser.Value = userid;
                            cmd.Parameters.Add(csuser);
                            cmd.Parameters.AddWithValue("@UserName", user.Name);
                            cmd.Parameters.AddWithValue("@Email", user.Name);
                            cmd.Parameters.AddWithValue("@PropertyNames", keys);
                            cmd.Parameters.AddWithValue("@PropertyValues", values);
                            cmd.Parameters.AddWithValue("@UserAccountStatus", 1);
                            cmd.Parameters.AddWithValue("@IsAnonymous", 0);
                            cmd.Parameters.AddWithValue("@IsIgnored", 0);
                            cmd.Parameters.AddWithValue("@AppUserToken", "");
                            cmd.Parameters.AddWithValue("@CreateDate", user.Datejoined);
                            SqlParameter IsApproved2 = new SqlParameter("@IsApproved", System.Data.SqlDbType.Bit);
                            IsApproved2.Value = 1;
                            cmd.Parameters.Add(IsApproved2);
                            cmd.Parameters.AddWithValue("@ForumView", 0);
                            cmd.Parameters.AddWithValue("@TimeZone", Convert.ToDouble(user.Timezone));
                            cmd.Parameters.AddWithValue("@PostRank", 0x0);
                            cmd.Parameters.AddWithValue("@PostSortOrder", 0);
                            cmd.Parameters.AddWithValue("@IsAvatarApproved", 0);
                            SqlParameter Force = new SqlParameter("@ForceLogin", System.Data.SqlDbType.Bit);
                            Force.Value = 1;
                            cmd.Parameters.Add(Force);
                            cmd.Parameters.AddWithValue("@ModerationLevel", 0);
                            cmd.Parameters.AddWithValue("@EnableThreadTracking", 0);
                            cmd.Parameters.AddWithValue("@EnableDisplayUnreadThreadsOnly", 0);
                            cmd.Parameters.AddWithValue("@EnableAvatar", 0);
                            cmd.Parameters.AddWithValue("@EnableDisplayInMemberList", 1);
                            cmd.Parameters.AddWithValue("@EnablePrivateMessages", 1);
                            cmd.Parameters.AddWithValue("@EnableOnlineStatus", 1);
                            cmd.Parameters.AddWithValue("@EnableEmail", (int)(user.EnableEmail ? 1 : 0));
                            cmd.Parameters.AddWithValue("@EnableHtmlEmail", 1);
                            cmd.Parameters.AddWithValue("@FavoritesShared", 0);
                            SqlParameter sitecontact = new SqlParameter("@AllowSiteToContact", System.Data.SqlDbType.Bit);
                            sitecontact.Value = 1;
                            cmd.Parameters.Add(sitecontact);
                            SqlParameter partcontact = new SqlParameter("@AllowSitePartnersToContact", System.Data.SqlDbType.Bit);
                            partcontact.Value = 0;
                            cmd.Parameters.Add(partcontact);
                            cmd.Parameters.AddWithValue("@SettingsID", sitesettingid);
                            cmd.Parameters.AddWithValue("@Action", 0);
                            cmd.Parameters.AddWithValue("@UpdateAllSettingsID", 0);
                            //                                                     cs user id,    asp.net user id, username,                                            email,                       profile keys, profile values, account status, anonymous, ignored, user token, Create Date, IsApproved, ForumView, TimeZone, PostRank, PostSortOrder, AvatarApproved, ForceLogin, Moderation Level,
                            //string b = "EXEC [dbo].[cs_user_CreateUpdateDelete] @cs_UserID OUTPUT, @UserID, N'" + user.Name.Replace("\'", string.Empty) + "', N'" + user.Email.Replace("\'", string.Empty) + "', N'" + keys + "', N'" + values + "', 1, 0, 0, '', '" + ConverteerDatum(user.Datejoined) + "', 1, 0, " + user.Timezone.ToString() + ", 0x0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, " + (user.EnableEmail ? 1 : 0).ToString() + ", 1, 0, 0, 0, " + sitesettingid.ToString() + ", 0, 0";
                            //sb.AppendLine(b);
                            cmd.ExecuteNonQuery();
                            cmd = new SqlCommand("[dbo].[aspnet_UsersInRoles_AddUsersToRoles]", con);
                            cmd.CommandType = CommandType.StoredProcedure;
                            cmd.Parameters.AddWithValue("@ApplicationName", settings["Application Name"].ToString());
                            cmd.Parameters.AddWithValue("@UserNames", user.Name);
                            cmd.Parameters.AddWithValue("@RoleNames", string.Join(",", rolenames.ToArray()));
                            cmd.Parameters.AddWithValue("@CurrentTimeUtc", DateTime.Now.ToUniversalTime());
                            //sb.AppendLine("EXEC	[dbo].[aspnet_UsersInRoles_AddUsersToRoles]	'" + settings["Application Name"].ToString() + "',N'" + user.Name.Replace("\'", string.Empty) + "','" + string.Join(",", rolenames.ToArray()) + "',@Time");
                            //cmd.CommandText = sb.ToString();
                            //con.Open();
                            cmd.ExecuteNonQuery();
                            con.Close();
                            users.Add(user);
                        #endregion
                            double aa = 0.00 + objects.Count;
                            status.Completed = Convert.ToInt32(Math.Round(Convert.ToDecimal(((x + 1) / aa) * 100), 0));
                            status.AddEvent(new Event(EventType.Information, "Created User " + user.Name, "Created User " + user.Name + "(" + user.Email + ")", DateTime.Now));
                        //}
                        //catch (Exception e) { status.AddEvent(new Event(EventType.MissingData, "Error Creating User", e.Message, e, DateTime.Now)); }
                        //sb.AppendLine("EXEC	[dbo].[aspnet_Membership_CreateUser] '" + settings["Application Name"].ToString() + "', '" + user.Name.Replace("\'", string.Empty) + "',N'" + password + "','',N'" + user.Email.Replace("\'", string.Empty) + "','Your Email?','" + user.Email.Replace("\'", string.Empty) + "',1, @Time, @Time, 1,0, @UserId OUTPUT");
                   
                    //}
                    //catch (Exception e)
                    //{
                    //    double aa = 0.00 + objects.Count;
                    //    status.Completed = Convert.ToInt32(Math.Round(Convert.ToDecimal(((x + 1) / aa) * 100), 0));
                    //    status.AddEvent(new Event(EventType.CriticalError, "Error Creating User " + user.Name, "Error Creating User " + user.Name + "(" + user.Email + ")", e, DateTime.Now));
                    //}
                }
            }
            con.Dispose();
        }

        #endregion

        public static string ConverteerDatum(DateTime in_Datum)
        {
            return in_Datum.Year + "-" + in_Datum.Month + "-" + in_Datum.Day + " " + in_Datum.ToLongTimeString();
        }
    }
}
